package com.gillion.grape.fros.ui.commands;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.java.amateras.uml.classdiagram.model.Argument;
import net.java.amateras.uml.classdiagram.model.AssociationModel;
import net.java.amateras.uml.classdiagram.model.AttributeModel;
import net.java.amateras.uml.classdiagram.model.ClassModel;
import net.java.amateras.uml.classdiagram.model.InterfaceModel;
import net.java.amateras.uml.classdiagram.model.OperationModel;
import net.java.amateras.uml.classdiagram.model.RelationType;
import net.java.amateras.uml.model.RootModel;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.ui.IFileEditorInput;

import com.gillion.grape.core.utils.Utils;
import com.gillion.grape.fros.core.data.TypeEntry;
import com.gillion.grape.fros.core.meta.GFAPropertyDomainType;
import com.gillion.grape.fros.ui.Entity2ERUtils;
import com.gillion.grape.fros.ui.Platform;

/**
 * 实体模型转换为GFA模型
 * 
 * @author meichenhui
 * @since 2011-8-24
 * 
 */
public class EntityPIM2GFAModel extends EntityPIM2PSM {

	@Override
	protected InputStream genTransformedModelFileContentStream() {
		try {
			return Utils.serialize(genGFAEntityModel());
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return null;
	}

	@Override
	protected IFile getTargetFile() {
		// 将GFA模型生成到实体模型所在的目录下
		IFileEditorInput input = (IFileEditorInput) Utils.getActivePage().getActiveEditor().getEditorInput();
		IProject prj = input.getFile().getProject();
		String openFileRelativePath = input.getFile().getProjectRelativePath().toString();
		String openFileFolderPath = openFileRelativePath.substring(0, openFileRelativePath.lastIndexOf("/"));
		return prj.getFile(openFileFolderPath + "/" + input.getName().split("\\.")[0] + ".gfa");
	}

	private RootModel genGFAEntityModel() {
		RootModel gfaRootModel = getRootModel();
		// 初始化GFA根节点模型
		List umlModels = gfaRootModel.getChildren();
		Map<String, List<ClassModel>> associations = new HashMap<String, List<ClassModel>>();
		int modelSize = umlModels.size();
		for (int i = 0; i < modelSize; i++) {
			if (!(umlModels.get(i) instanceof ClassModel)) {
				continue; // 只对类模型进行处理
			}
			// 初始化实体类
			ClassModel gfaEntityClass = (ClassModel) umlModels.get(i);
			String entityPackage = getModuleName() + ".entity.";
			String entityDomainPackage = entityPackage + "domain.";
			String servicePackage = getModuleName() + ".service.";
			gfaEntityClass.setName(entityPackage + gfaEntityClass.getSimpleName());

			// 添加主键
			AttributeModel primaryKey = new AttributeModel(); // 主键
			primaryKey.setName(Entity2ERUtils.genPrimaryKeyProperty(gfaEntityClass.getSimpleName()));
			primaryKey.setType("string(50)");
			// 主键国际化
			primaryKey.setSimplifiedChinese(gfaEntityClass.getSimplifiedChinese());
			primaryKey.setTraditionalChinese(gfaEntityClass.getTraditionalChinese());
			primaryKey.setEnglish(gfaEntityClass.getEnglish());
			gfaEntityClass.addChild(primaryKey);
			
			if (!gfaEntityClass.isViewEntity() && !gfaEntityClass.isVoEntity()) {
              if("templates/java_service_impl_logic.jet".equals(gfaEntityClass.getDeleteTemplate())){//逻辑删除则添加删除标识 
	             AttributeModel delFlag = new AttributeModel();
	             delFlag.setName("delFlag");
	             delFlag.setType("boolean");
	             gfaEntityClass.addChild(delFlag);
                }
				// 添加实体类的系统默认属性
				AttributeModel createByUser = new AttributeModel(); // 创建人
				createByUser.setName("createdByUser");
				createByUser.setType("string(50)");
				// 创建人国际化
				createByUser.setSimplifiedChinese("创建人");
				createByUser.setTraditionalChinese("创建人");
				createByUser.setEnglish("createByUser");
				gfaEntityClass.addChild(createByUser);


				AttributeModel createdDtmLoc = new AttributeModel(); // 创建时间
				createdDtmLoc.setName("createdDtmLoc");
				createdDtmLoc.setType("date");
				// 创建时间
				createdDtmLoc.setSimplifiedChinese("创建时间");
				createdDtmLoc.setTraditionalChinese("创建时间");
				createdDtmLoc.setEnglish("createdDtmLoc");
				gfaEntityClass.addChild(createdDtmLoc);


				AttributeModel updatedByUser = new AttributeModel(); // 最后修改人
				updatedByUser.setName("updatedByUser");
				updatedByUser.setType("string(50)");
				// 修改人
				updatedByUser.setSimplifiedChinese("修改人");
				updatedByUser.setTraditionalChinese("修改人");
				updatedByUser.setEnglish("updatedByUser");
				gfaEntityClass.addChild(updatedByUser);

				AttributeModel updatedDtmLoc = new AttributeModel(); // 最后修改时间
				updatedDtmLoc.setName("updatedDtmLoc");
				updatedDtmLoc.setType("date");
				// 修改时间
				updatedDtmLoc.setSimplifiedChinese("修改时间");
				updatedDtmLoc.setTraditionalChinese("修改时间");
				updatedDtmLoc.setEnglish("updatedDtmLoc");
				gfaEntityClass.addChild(updatedDtmLoc);

				AttributeModel recordVersion = new AttributeModel(); // 版本锁
				recordVersion.setName("recVer");
				recordVersion.setType("integer(10)");
				gfaEntityClass.addChild(recordVersion);
			}
			
				// 初始化Domain类
				ClassModel gfaDomainClass = new ClassModel();
				gfaDomainClass.setForegroundColor(gfaEntityClass.getForegroundColor().getRGB());
				gfaDomainClass.setBackgroundColor(gfaEntityClass.getBackgroundColor().getRGB());
//				gfaDomainClass.setConstraint(gfaEntityClass.getConstraint().getCopy().translate(70, 25));
				gfaDomainClass.setName(entityDomainPackage + gfaEntityClass.getSimpleName() + "Domain");
				gfaRootModel.addChild(gfaDomainClass);

				// Domain类的className属性
				AttributeModel className = new AttributeModel();
				className.setName(gfaEntityClass.getSimpleName());
				className.setType("string");
				gfaDomainClass.getChildren().add(className);
				className.setDomainType(GFAPropertyDomainType.WHOLECLASSNAME.name());

				// Domain类的classNameNLS属性
				AttributeModel classNameNLS = new AttributeModel();
				classNameNLS.setName(gfaEntityClass.getSimpleName() + "NLS");
				classNameNLS.setType("string");
				classNameNLS.setDomainType(GFAPropertyDomainType.NLS.name());
				gfaDomainClass.getChildren().add(classNameNLS);
				
				gfaDomainClass.setVoEntity(gfaEntityClass.isVoEntity());

			if (!gfaEntityClass.isViewEntity() && !gfaEntityClass.isVoEntity()) {
				// 初始化Service接口
				InterfaceModel gfaInterface = new InterfaceModel();
				gfaInterface.setName(servicePackage + gfaEntityClass.getSimpleName() + "Service");
				gfaInterface.setForegroundColor(gfaEntityClass.getForegroundColor().getRGB());
				gfaInterface.setBackgroundColor(gfaEntityClass.getBackgroundColor().getRGB());
//				gfaInterface.setConstraint(gfaDomainClass.getConstraint().getCopy().translate(70, 25));
				gfaInterface.setViewEntity(gfaEntityClass.isViewEntity());
				gfaRootModel.addChild(gfaInterface);
				genServiceOperations(gfaInterface); // 生成接口方法

				// 初始化Service的impl类
				ClassModel gfaServiceImpl = genServiceImplClass(gfaInterface);
				gfaServiceImpl.setViewEntity(gfaInterface.isViewEntity());
				gfaServiceImpl.setParentService(gfaEntityClass.getParentService());
				gfaServiceImpl.setDeleteTemplate(gfaEntityClass.getDeleteTemplate());
				gfaRootModel.addChild(gfaServiceImpl);

			}

			// 属性处理
			List classElements = gfaEntityClass.getChildren();
			for (int j = classElements.size() - 1; j >= 0; j--) { // 生成get,set方法,Domain类的属性
				Object oneClassElement = classElements.get(j);
				if (!(oneClassElement instanceof AttributeModel)) {
					continue;
				}
				AttributeModel attribute = (AttributeModel) oneClassElement;

				// model类型 转成Java类型
				TypeEntry attributeTypeEntry = new TypeEntry(attribute.getType(), Platform.MODEL, Platform.JAVA);
				attribute.setType(attributeTypeEntry.getDataTypeName());
				attribute.setTypeLenExpression(attributeTypeEntry.getLenExpression());

				// 属性名转换 itemName --> ItemName
				String operationName = Entity2ERUtils.upperTitle(attribute.getName());
				// 属性类型
				String javaType = "string";
				genEntityGetterSetter(operationName, javaType, gfaEntityClass); // 构造实体类的get,set方法
				genDomainAttributes(attribute, gfaDomainClass); // 构造Domain类的属性
			}
			// 实体关系生成子表集合和主表对象印象
			// source
			List<AssociationModel> sourceAssociations = (List<AssociationModel>) gfaEntityClass.getModelSourceConnections();
			for (AssociationModel oneAssociation : sourceAssociations) {
				if ("1".equals(oneAssociation.getFromMultiplicity()) && "*".equals(oneAssociation.getToMultiplicity())) { // 主表,添加子表的集合
					AttributeModel childSet = new AttributeModel();
					ClassModel child = (ClassModel) oneAssociation.getTarget();
					childSet.setDomainType(GFAPropertyDomainType.NORMAL.name());
					childSet.setType("Set<" + child.getSimpleName() + ">");
					childSet.setName(Entity2ERUtils.lowerTitle(child.getSimpleName()) + "s");
					childSet.setLazyO2M(oneAssociation.getLazyO2M());
					childSet.setRelation(RelationType.ONE2MANY);
					childSet.setCascade(oneAssociation.getCascade4Many());
					gfaEntityClass.addChild(childSet);
					gfaDomainClass.addChild(childSet);
				}
				if ("1".equals(oneAssociation.getFromMultiplicity()) && "1".equals(oneAssociation.getToMultiplicity())) { // 主表,添加子表的集合
					AttributeModel childSet = new AttributeModel();
					ClassModel child = (ClassModel) oneAssociation.getTarget();
					childSet.setDomainType(GFAPropertyDomainType.NORMAL.name());
					childSet.setType(child.getSimpleName());
					childSet.setName(Entity2ERUtils.lowerTitle(child.getSimpleName()));
					childSet.setLazyO2M(oneAssociation.getLazyO2M());
					childSet.setRelation(RelationType.ONE2ONE);
					childSet.setCascade(oneAssociation.getCascade4Many());
					gfaEntityClass.addChild(childSet);
					gfaDomainClass.addChild(childSet);
				}
				if ("*".equals(oneAssociation.getFromMultiplicity())) { // 子表,添加主表对象
					AttributeModel parentQuote = new AttributeModel();
					ClassModel parent = (ClassModel) oneAssociation.getTarget();
					parentQuote.setDomainType(GFAPropertyDomainType.NORMAL.name());
					parentQuote.setType(parent.getSimpleName());
					parentQuote.setName(Entity2ERUtils.lowerTitle(parent.getSimpleName()));
					parentQuote.setLazyM2O(oneAssociation.getLazyM2O());
					parentQuote.setRelation(RelationType.MANY2ONE);
					parentQuote.setCascade(oneAssociation.getCascade4One());
					gfaEntityClass.addChild(parentQuote);
					gfaDomainClass.addChild(parentQuote);
				}
			}
			// target
			List<AssociationModel> targetAssociations = (List<AssociationModel>) gfaEntityClass.getModelTargetConnections();
			for (AssociationModel oneAssociation : targetAssociations) {
				if ("*".equals(oneAssociation.getToMultiplicity())) { // 子表,添加主表对象
					AttributeModel parentQuote = new AttributeModel();
					ClassModel parent = (ClassModel) oneAssociation.getSource();
					parentQuote.setDomainType(GFAPropertyDomainType.NORMAL.name());
					parentQuote.setType(parent.getSimpleName());
					parentQuote.setName(Entity2ERUtils.lowerTitle(parent.getSimpleName()));
					parentQuote.setLazyM2O(oneAssociation.getLazyM2O());
					parentQuote.setRelation(RelationType.MANY2ONE);
					parentQuote.setCascade(oneAssociation.getCascade4One());
					gfaEntityClass.addChild(parentQuote);
					gfaDomainClass.addChild(parentQuote);
				}
				if ("1".equals(oneAssociation.getToMultiplicity()) && "*".equals(oneAssociation.getFromMultiplicity())) { // 主表,添加子表的集合
					AttributeModel childSet = new AttributeModel();
					ClassModel child = (ClassModel) oneAssociation.getSource();
					childSet.setDomainType(GFAPropertyDomainType.NORMAL.name());
					childSet.setType("Set<" + child.getSimpleName() + ">");
					childSet.setName(Entity2ERUtils.lowerTitle(child.getSimpleName()) + "s");
					childSet.setLazyO2M(oneAssociation.getLazyO2M());
					childSet.setRelation(RelationType.ONE2MANY);
					childSet.setCascade(oneAssociation.getCascade4Many());
					gfaEntityClass.addChild(childSet);
					gfaDomainClass.addChild(childSet);
				}
				if ("1".equals(oneAssociation.getToMultiplicity()) && "1".equals(oneAssociation.getFromMultiplicity())) { // 主表,添加子表的集合
					AttributeModel childObject = new AttributeModel();
					ClassModel child = (ClassModel) oneAssociation.getSource();
					childObject.setDomainType(GFAPropertyDomainType.NORMAL.name());
					childObject.setType("java.lang.String");
					childObject.setName(Entity2ERUtils.lowerTitle(child.getSimpleName()) + "Id");
					childObject.setLazyO2M(oneAssociation.getLazyO2M());
					childObject.setRelation(RelationType.ONE2ONESUB);
					childObject.setCascade(oneAssociation.getCascade4Many());
					gfaEntityClass.addChild(childObject);
					gfaDomainClass.addChild(childObject);
				}
			}
		}
		return gfaRootModel;
	}

	/**
	 * 生成service的impl类
	 * 
	 * @param serviceInterface
	 * @return
	 * 
	 * @author meichenhui
	 * @since 2011-8-25
	 * 
	 */
	private ClassModel genServiceImplClass(InterfaceModel serviceInterface) {
		ClassModel implClass = new ClassModel();
		implClass.setName(getModuleName() + ".impl." + serviceInterface.getSimpleName() + "Impl");
		implClass.setForegroundColor(serviceInterface.getForegroundColor().getRGB());
		implClass.setBackgroundColor(serviceInterface.getBackgroundColor().getRGB());
//		implClass.setConstraint(serviceInterface.getConstraint().getCopy().translate(70, 25));
		List serviceInterfaceElements = serviceInterface.getChildren();
		for (Object oneElement : serviceInterfaceElements) { // 构造impl类的方法
			if (!(oneElement instanceof OperationModel)) {
				continue;
			}
			OperationModel operation = (OperationModel) oneElement;
			implClass.addChild((OperationModel) operation.clone());
		}
		return implClass;
	}

	/**
	 * 构造service接口的方法
	 * 
	 * @param serviceInterface
	 * 
	 * @author meichenhui
	 * @since 2011-8-25
	 * 
	 */
	private void genServiceOperations(InterfaceModel serviceInterface) {
		String entityClassSimpleName = serviceInterface.getSimpleName().substring(0, serviceInterface.getSimpleName().length() - 7);
		// add
		OperationModel add = new OperationModel();
		String addName = "add" + entityClassSimpleName;
		add.setName(addName);
		add.setType(entityClassSimpleName);
		serviceInterface.addChild(add);
		Argument addArg = new Argument();
		addArg.setName(Entity2ERUtils.lowerTitle(entityClassSimpleName));
		addArg.setType(entityClassSimpleName);
		add.getParams().add(addArg);
		// update
		OperationModel update = new OperationModel();
		String updateName = "update" + entityClassSimpleName;
		update.setName(updateName);
		update.setType(entityClassSimpleName);
		serviceInterface.addChild(update);
		Argument updateArg = new Argument();
		updateArg.setName(Entity2ERUtils.lowerTitle(entityClassSimpleName));
		updateArg.setType(entityClassSimpleName);
		update.getParams().add(updateArg);
		// remove
		OperationModel remove = new OperationModel();
		String removeName = "remove" + entityClassSimpleName;
		remove.setName(removeName);
		serviceInterface.addChild(remove);
		Argument removeArg = new Argument();
		removeArg.setName(Entity2ERUtils.lowerTitle(entityClassSimpleName));
		removeArg.setType(entityClassSimpleName);
		remove.getParams().add(removeArg);
		// saveOrUpdate
		OperationModel saveOrUpdate = new OperationModel();
		String saveOrUpdateName = "saveOrUpdate" + entityClassSimpleName;
		saveOrUpdate.setName(saveOrUpdateName);
		serviceInterface.addChild(saveOrUpdate);
		Argument saveOrUpdateArg = new Argument();
		saveOrUpdateArg.setName(Entity2ERUtils.lowerTitle(entityClassSimpleName));
		saveOrUpdateArg.setType(entityClassSimpleName);
		saveOrUpdate.getParams().add(saveOrUpdateArg);
		// saveOrUpdates
		OperationModel saveOrUpdates = new OperationModel();
		String saveOrUpdatesName = "saveOrUpdate" + entityClassSimpleName + "s";
		saveOrUpdates.setName(saveOrUpdatesName);
		serviceInterface.addChild(saveOrUpdates);
		Argument saveOrUpdatesArg = new Argument();
		saveOrUpdatesArg.setName(Entity2ERUtils.lowerTitle(entityClassSimpleName));
		saveOrUpdatesArg.setType("Set<" + entityClassSimpleName + ">");
		saveOrUpdates.getParams().add(saveOrUpdatesArg);
	}

	/**
	 * 构造Domain类中的属性
	 * 
	 * @param attribute
	 * @param domainClass
	 * 
	 * @author meichenhui
	 * @since 2011-8-25
	 * 
	 */
	private void genDomainAttributes(AttributeModel attribute, ClassModel domainClass) {
		if(attribute.isVerticalExtendField())
			return;
		// attribute simple name
		AttributeModel simpleName = new AttributeModel();
		simpleName.setName(attribute.getName());
		simpleName.setType("String");
		simpleName.setDomainType(GFAPropertyDomainType.NORMAL.name());
		domainClass.getChildren().add(0, simpleName);
		// attribute full name
		AttributeModel fullName = new AttributeModel();
		fullName.setName(attribute.getName().concat("_full"));
		fullName.setType("String");
		fullName.setDomainType(GFAPropertyDomainType.FULL.name());
		domainClass.getChildren().add(fullName);
	}

	/**
	 * 实体类的get,set方法
	 * 
	 * @param attribute
	 * @param type
	 * @param entityClass
	 * 
	 * @author meichenhui
	 * @since 2011-8-25
	 * 
	 */
	private void genEntityGetterSetter(String attribute, String type, ClassModel entityClass) {
		// get
		OperationModel getter = new OperationModel();
		String getterName = "get" + attribute;
		getter.setName(getterName);
		getter.setType(type);
		entityClass.addChild(getter);
		// set
		OperationModel setter = new OperationModel();
		String setterName = "set" + attribute;
		setter.setName(setterName);
		Argument arg = new Argument();
		arg.setName(Entity2ERUtils.lowerTitle(attribute));
		arg.setType(type);
		List paramList = new ArrayList();
		paramList.add(arg);
		setter.setParams(paramList);
		setter.setType("void");
		entityClass.addChild(setter);
	}
}
